﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Collections;

namespace CitrixPVSWrapper
{
    
    [System.Management.Automation.Cmdlet("Run", "PvsAssignAuthGroup", SupportsShouldProcess = true)]
    public class Run_PvsAssignAuthGroup : System.Management.Automation.PSCmdlet
    {
        [Parameter(Mandatory = false)]
        public PvsAuthGroup AuthGroup;

        [Parameter(Mandatory = false)]
        public String AuthGroupId;

        [Parameter(Mandatory = false)]
        public String AuthGroupName;

        [Parameter(ParameterSetName = "Collection", Mandatory = true)]
        public PvsCollection Collection;

        [Parameter(ParameterSetName = "CollectionId", ValueFromPipelineByPropertyName = true, Mandatory = true)]
        public string CollectionId;

        [Parameter(ParameterSetName = "CollectionName", Mandatory = true)]
        [Parameter(ParameterSetName = "CollectionName-SiteName", Mandatory = true)]
        [Parameter(ParameterSetName = "CollectionName-SiteId", Mandatory = true)]
        [Parameter(ParameterSetName = "CollectionName-Site", Mandatory = true)]
        public string CollectionName;

        [Parameter(ParameterSetName = "Site", Mandatory = true)]
        [Parameter(ParameterSetName = "CollectionName-Site", Mandatory = true)]
        public PvsSite Site;

        [Parameter(ParameterSetName = "SiteId", ValueFromPipelineByPropertyName = true, Mandatory = true)]
        [Parameter(ParameterSetName = "CollectionName-SiteId", Mandatory = true)]
        public string SiteId;

        [Parameter(ParameterSetName = "SiteName", Mandatory = true)]
        [Parameter(ParameterSetName = "CollectionName-SiteName", Mandatory = true)]
        public string SiteName;

        [Parameter(ParameterSetName = "Collection", Mandatory = false)]
        [Parameter(ParameterSetName = "CollectionId", Mandatory = false)]
        [Parameter(ParameterSetName = "CollectionName", Mandatory = false)]
        [Parameter(ParameterSetName = "CollectionName-SiteName", Mandatory = false)]
        [Parameter(ParameterSetName = "CollectionName-SiteId", Mandatory = false)]
        [Parameter(ParameterSetName = "CollectionName-Site", Mandatory = false)]
        [ValidateSet("300", "400")]
        public String Role = "400";

        protected override void BeginProcessing()
        {
            // Test for mutually exclusive parameters
            Validate.MutuallyExclusiveParameters(this.MyInvocation.BoundParameters, new string[] { "AuthGroup", "AuthGroupId", "AuthGroupName" },true);

            // Test that the supplied Auth Group exists
            if (MyInvocation.BoundParameters.ContainsKey("AuthGroup")) 
            {
                if (Get_PvsAuthGroup_Internal.Get_AuthGroupById(this.AuthGroup.AuthGroupId).Count == 1)
                {
                    this.AuthGroupId = this.AuthGroup.AuthGroupId;
                    this.AuthGroupName = this.AuthGroup.AuthGroupName;
                }
                else
                {
                    throw new ParameterBindingException("The specified authorization group could not be found");
                }
            }
            else if (MyInvocation.BoundParameters.ContainsKey("AuthGroupId")) 
            {
                if (Get_PvsAuthGroup_Internal.Get_AuthGroupById(this.AuthGroupId).Count == 1)
                {
                    this.AuthGroup = Get_PvsAuthGroup_Internal.Get_AuthGroupById(this.AuthGroupId).First();
                    this.AuthGroupName = this.AuthGroup.AuthGroupName;
                }
                else
                {
                    throw new ParameterBindingException("The specified authorization group Id could not be found");
                }
            }
            else if (MyInvocation.BoundParameters.ContainsKey("AuthGroupName")) 
            {
                if (Get_PvsAuthGroup_Internal.Get_AuthGroupByName(this.AuthGroupName).Count == 1)
                {
                    this.AuthGroup = Get_PvsAuthGroup_Internal.Get_AuthGroupByName(this.AuthGroupName).First();
                    this.AuthGroupId = this.AuthGroup.AuthGroupId;
                }
                else
                {
                    throw new ParameterBindingException("The specified authorization group name could not be found");
                }
            }
        }

        protected override void ProcessRecord()
        {
            // Verbose and Debug Settings
            Boolean Verbose = this.MyInvocation.BoundParameters.ContainsKey("Verbose");
            WriteVerbose("Verbose Flag: " + Verbose);
            Boolean Debug = this.MyInvocation.BoundParameters.ContainsKey("Debug");
            WriteDebug("Debug Flag: " + Debug);

            // Collections to hold the queries and the results
            Collection<QueryDefinition> RunQueries = new Collection<QueryDefinition>();
            string TargetObject = "AssignAuthGroup";

            // Build the queries based on the parameter sets
            switch (this.ParameterSetName)
            {
                case "Collection":
                    {
                        RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "CollectionId=\"" + this.Collection.CollectionId + "\""));
                        break;
                    }

                case "CollectionId":
                    {
                        RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "CollectionId=\"" + this.CollectionId + "\""));
                        break;
                    }

                case "CollectionName":
                    {
                        foreach (PvsCollection QryCollection in Get_PvsCollection_Internal.Get_CollectionByName(this.CollectionName, Verbose))
                        { RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "CollectionId=\"" + QryCollection.CollectionId + "\"")); }
                        break;
                    }

                case "CollectionName-Site":
                    {
                        foreach (PvsCollection QryCollection in Get_PvsCollection_Internal.Get_CollectionByNameAndSiteId(this.CollectionName, this.Site.SiteId, Verbose))
                        { RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "CollectionId=\"" + QryCollection.CollectionId + "\"")); }
                        break;
                    }

                case "CollectionName-SiteId":
                    {
                        foreach (PvsCollection QryCollection in Get_PvsCollection_Internal.Get_CollectionByNameAndSiteId(this.CollectionName, this.SiteId, Verbose))
                        { RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "CollectionId=\"" + QryCollection.CollectionId + "\"")); }
                        break;
                    }

                case "CollectionName-SiteName":
                    {
                        foreach (PvsCollection QryCollection in Get_PvsCollection_Internal.Get_CollectionByNameAndSiteName(this.CollectionName, this.SiteName, Verbose))
                        { RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "CollectionId=\"" + QryCollection.CollectionId + "\"")); }
                        break;
                    }

                case "Site":
                    {
                        RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "SiteId=\"" + this.Site.SiteId + "\""));
                        break;
                    }

                case "SiteId":
                    {
                        RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "SiteId=\"" + this.SiteId + "\""));
                        break;
                    }

                case "SiteName":
                    {
                        foreach (PvsSite QrySite in Get_PvsSite_Internal.Get_SiteByName(this.SiteName, Verbose))
                        { RunQueries.Add(new QueryDefinition(QueryActionType.Run, TargetObject, "SiteId=\"" + QrySite.SiteId + "\"")); }
                        break;
                    }

            }

            // Test that we have a suitable object to perform the Run with, and build the confirmation message
            if (RunQueries.Count() == 0)
            {
                WriteError(new ErrorRecord(new InvalidOperationException("No items were found to assign to using the supplied parameters"), "1", ErrorCategory.InvalidArgument, null));
            }

            // Execute the run queries
            foreach (QueryDefinition RunQuery in RunQueries)
            {
                // Add in the mandatory parameters
                RunQuery.Parameters.Add("authGroupId=\"" + this.AuthGroupId + "\"");

                // Add in the optional parameters if they have been specified
                if (MyInvocation.BoundParameters.ContainsKey("Role")) { RunQuery.Parameters.Add("role=\"" + this.Role + "\""); }

                string objectId;
                string objectName;
                string ShouldProcessMessage;

                // Check that we have a valid parameter to work with, extract the object id/name and build the ShouldProcess message
                if (RunQuery.Parameters.Where(p => p.StartsWith("CollectionId")).Count() == 1)
                {
                    objectId = RunQuery.Parameters.Where(p => p.StartsWith("CollectionId")).First().Split('=')[1].Replace('"', ' ').Trim();
                    if (Get_PvsCollection_Internal.Get_CollectionById(objectId).Count() != 1)
                    {
                        WriteError(new ErrorRecord(new InvalidOperationException(String.Format("Collection Id {0} does not exist", objectId)), "2", ErrorCategory.InvalidArgument, null));
                        continue;
                    }
                    objectName = Get_PvsCollection_Internal.Get_CollectionById(objectId).First().CollectionName;
                    ShouldProcessMessage = String.Format("Assign authorization group {0} to collection {0} with collection Id {1}", AuthGroupId, objectName, objectId);
                }

                else if (RunQuery.Parameters.Where(p => p.StartsWith("SiteId")).Count() == 1)
                {
                    objectId = RunQuery.Parameters.Where(p => p.StartsWith("SiteId")).First().Split('=')[1].Replace('"', ' ').Trim();
                    if (Get_PvsSite_Internal.Get_SiteById(objectId).Count() != 1)
                    {
                        WriteError(new ErrorRecord(new InvalidOperationException(String.Format("Site Id {0} does not exist", objectId)), "2", ErrorCategory.InvalidArgument, null));
                        continue;
                    }
                    objectName = Get_PvsSite_Internal.Get_SiteById(objectId).First().SiteName;
                    ShouldProcessMessage = String.Format("Assign authorization group {0} to site {0} with site Id {1}", AuthGroupId, objectName, objectId);
                }

                else
                {
                    WriteError(new ErrorRecord(new InvalidOperationException("Query does not contain any valid targets"), "2", ErrorCategory.InvalidArgument, null));
                    continue;
                }

                // Perform the actual run and return any errors
                if (ShouldProcess(ShouldProcessMessage))
                {
                    MCliReturnObject Return = PvsHelpers.ExecuteMcliAction(RunQuery, Verbose, Debug);
                    if (Return.ReturnState == ReturnState.Error) { foreach (ErrorRecord Error in Return.Errors) { WriteError(Error); } }
                }

            }

        }
    }
}
